/*********************************************************************************
 *      Copyright:  (C) 2025 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  get_temp.cpp
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(29/09/25)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "29/09/25 10:55:41"
 *                 
 ********************************************************************************/

#include "get_temp.hpp"

namespace IotClient {

Ds18b20Sensor::Ds18b20Sensor()
{
    if(findChipId() != 0)
    {
        std::cerr << "WARN: DS18B20 sensor initialization failed : could not dinf chip ID." << std::endl;
    }
}

int Ds18b20Sensor::findChipId()
{
    DIR *dirp = opendir(w1_path.c_str());
    if(dirp == nullptr)
    {
        std::cerr << "ERROR:opendir" << w1_path << " failed" << std::strerror(errno) << std::endl;
        return -1;
    }

    struct dirent *direntp;
    while((direntp = readdir(dirp)) != nullptr)
    {
        std::string d_name(direntp->d_name);
        if(d_name.find("28-") == 0)
        {
            chip_id = d_name;
            closedir(dirp);
            return 0;
        }
    }

    closedir(dirp);
    return -2;
}

float Ds18b20Sensor::getTemperature()
{
    if(chip_id.empty())
    {
        throw std::runtime_error("sensor not initialized or chip Id not found");
    }

    std::string ds_path = w1_path + chip_id + "/w1_slave";

    std::ifstream ifs(ds_path);
    if(!ifs.is_open())
    {
        throw std::runtime_error("failed to open w1 slave file: " + ds_path);
    }

    //一个内存中的流对象
    //数据写入可以用<<（流插入符），数据读取可以用>>（流提取符）
    //大小自动管理，自动调整内部缓冲区大小，不用担心溢出
    std::stringstream buffer;
    buffer << ifs.rdbuf();
    std::string content = buffer.str(); //返回buffer内部当前存储的所有字符数据，作为一个完整的std::string对象

    size_t pos = content.find("t=");
    if(pos == std::string::npos)
    {
        throw std::runtime_error("Could not find temperature 't=' in sensor data.");
    }

    std::string temp_str = content.substr(pos + 2);

    try
    {
        float raw_temp = std::stof(temp_str); //string to float
        return raw_temp / 1000.0f;
    }
    catch(const std::exception& e)
    {
        throw std::runtime_error("Temperature string conversion failed: " + std::string(e.what()));
    }
}

std::string SystemInfo::getSystemTime()
{
    std::time_t rawtime;

    //if get time failure 
    if(std::time(&rawtime) == (std::time_t)-1)
    {
        throw std::runtime_error("failed to get raw systime time");
    }

    struct tm *tim = std::localtime(&rawtime);
    if(!tim)
    {
        throw std::runtime_error("failed to convert raw time to local time struct");
    }

    std::stringstream ss;
    ss << (tim->tm_year + 1900) << "-" 
       << std::setw(2) << std::setfill('0') << (tim->tm_mon + 1) << "-" 
       << std::setw(2) << std::setfill('0') << tim->tm_mday << " " 
       << std::setw(2) << std::setfill('0') << tim->tm_hour << ":" 
       << std::setw(2) << std::setfill('0') << tim->tm_min << ":" 
       << std::setw(2) << std::setfill('0') << tim->tm_sec;

    return ss.str();
}

std::string SystemInfo::getDevicedId()
{
    std::stringstream ss;
    ss << "RIP-" << std::setw(3) << std::setfill('0') << DEFAULT_SN;

    return ss.str();
}

}
